<!--
 * Tencent is pleased to support the open source community by making BK-JOB蓝鲸智云作业平台 available.
 *
 * Copyright (C) 2021 THL A29 Limited, a Tencent company.  All rights reserved.
 *
 * BK-JOB蓝鲸智云作业平台 is licensed under the MIT License.
 *
 * License for BK-JOB蓝鲸智云作业平台:
 *
 *
 * Terms of the MIT License:
 * ---------------------------------------------------
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
-->

<template>
	<div class="task-import-step2">
		<div class="package-upload">
			<bk-upload
				v-if="!uploadFilename"
				:custom-request="handleUploadRequest"
				:multiple="false"
				:size="Infinity"
				:tip="$t('template.仅支持上传来自作业平台专属导出的压缩包')"
				url="/"
			/>
			<div v-if="uploadFilename" class="upload-result" :class="uploadStatus">
				<div class="file-pic">
					<img src="/static/images/package.svg" />
				</div>
				<div class="file-info">
					<div class="file-name">
						{{ uploadFilename }}
					</div>
					<div v-if="uploadStatus === 'waiting'" class="upload-progress">
						<div class="progress-bar" :style="{ width: uploadProgress }" />
					</div>
					<div v-if="uploadStatus === 'success'" class="file-status">
						{{ $t('template.上传成功') }}
					</div>
					<div v-if="uploadStatus === 'failed'" class="file-status">
						{{ $t('template.上传失败') }}
					</div>
					<div v-if="uploadStatus === 'error'" class="file-status">
						{{ uploadErrorMsg }}
					</div>
				</div>
				<icon
					v-if="uploadStatus === 'failed'"
					class="file-refresh"
					type="refresh"
					@click="handleFileRefresh"
				/>
				<icon class="file-delete" type="close-big" @click="hanleFileDelete" />
			</div>
		</div>
		<div
			v-if="isShowLog"
			v-bkloading="{ isLoading: isLogLoading }"
			class="upload-log-box"
			@click="handleLogAction"
		>
			<div
				v-for="(item, index) in importInfo.log"
				:key="index"
				v-html="renderLogRow(item, index, importInfo.log)"
			/>
		</div>
		<action-bar>
			<bk-button class="mr10" @click="handleCancel">
				{{ $t('template.取消') }}
			</bk-button>
			<bk-button class="mr10" @click="handleLast">
				{{ $t('template.上一步') }}
			</bk-button>
			<bk-button class="w120" :disabled="!isUploadSuccess" theme="primary" @click="handleNext">
				{{ $t('template.下一步') }}
			</bk-button>
		</action-bar>
		<lower-component :custom="isShowPassword" level="custom">
			<jb-dialog
				v-model="isShowPassword"
				class="setting-password-dialog"
				:esc-close="false"
				header-position="left"
				:mask-close="false"
				render-directive="if"
				:title="$t('template.文件包解密确认')"
				:width="480"
			>
				<jb-form ref="passwordForm" form-type="vertical" :model="passwordFormData" :rules="rules">
					<jb-form-item :label="$t('template.文件包密码')" property="password" required>
						<bk-input
							v-model="passwordFormData.password"
							:native-attributes="{ autofocus: 'autofocus' }"
							:placeholder="$t('template.请输入上传的文件包密码，完成后点提交验证')"
							type="password"
							@keydown="handleEnter"
						/>
					</jb-form-item>
				</jb-form>
				<div slot="footer" class="setting-password-footer">
					<bk-button
						class="mr10"
						:loading="isPasswordSubmiting"
						theme="primary"
						@click="handleSubmitPassword"
					>
						{{ $t('template.提交') }}
					</bk-button>
					<bk-button @click="handleClosePassword">
						{{ $t('template.取消') }}
					</bk-button>
				</div>
			</jb-dialog>
		</lower-component>
	</div>
</template>
<script>
import BackupService from '@service/backup';

import { prettyDateTimeFormat } from '@utils/assist';
import { taskImport } from '@utils/cache-helper';

import I18n from '@/i18n';

import ActionBar from '../components/action-bar';

const escapeHTML = str =>
	str.replace(/&/g, '&#38;').replace(/"/g, '&#34;').replace(/'/g, '&#39;').replace(/</g, '&#60;');

const TASK_STATUS_DEFAULT = 0;
const TASK_STATUS_PACKAGE_PARSE_SUCCESS = 1;
const TASK_STATUS_NEED_PASSWORD = 2;
const TASK_STATUS_ERROR_PASSWORD = 3;
const TASK_STATUS_PENDING = 5;
const TASK_STATUS_CANCEL = 8;

const LOG_TYPE_TASK_EXPIRE = 2;
const LOG_TYPE_NEED_PASSWORD = 6;
const LOG_TYPE_ERROR_PASSWORD = 7;

export default {
	name: '',
	components: {
		ActionBar,
	},
	data() {
		return {
			isShowPassword: false,
			isShowLog: false,
			isLogLoading: false,
			isPasswordSubmiting: false,
			id: '',
			importInfo: {
				id: '',
				log: [],
				status: 0,
				templateInfo: [],
			},
			passwordFormData: {
				password: '',
			},
			uploadProgress: '0',
			uploadFilename: '',
			uploadStatus: '', // waiting: 上传中；failed: 上传失败；success: 上传成功；
		};
	},

	computed: {
		isUploadSuccess() {
			return this.importInfo.status === TASK_STATUS_PACKAGE_PARSE_SUCCESS;
		},
	},

	created() {
		this.fileMemo = null;
		this.uploadErrorMsg = '';
		this.pollingQueue = [];
		this.rules = {
			password: [{ required: true, message: I18n.t('template.请输入文件包密码'), trigger: 'blur' }],
		};
		this.uploadRequestCancelSource = null;
		const { id, uploadFilename } = taskImport.getItem() || {};
		if (id && uploadFilename) {
			this.uploadFilename = uploadFilename;
			this.uploadStatus = 'success';
			this.importInfo.status = TASK_STATUS_PACKAGE_PARSE_SUCCESS;
			this.id = id;
			this.fetchImportInfo();
			this.startTimer();
		}
	},

	beforeDestroy() {
		this.clearTimer();
	},

	methods: {
		fetchImportInfo() {
			this.isShowLog = true;
			this.$request(
				BackupService.fetchImportInfo({
					id: this.id,
				}),
				() => {
					this.isLogLoading = true;
				}
			)
				.then(data => {
					if (this.isClearTimer) {
						return;
					}
					this.importInfo = Object.freeze(data);
					if (data.status === TASK_STATUS_NEED_PASSWORD) {
						// 需要密码自动弹框
						this.handleInputPassword();
						return;
					}
					if (data.status === TASK_STATUS_ERROR_PASSWORD) {
						// 密码错误
						return;
					}
					if (
						[TASK_STATUS_DEFAULT, TASK_STATUS_PENDING, TASK_STATUS_CANCEL].includes(data.status)
					) {
						// 循环获取日志
						this.pollingQueue.push(this.fetchImportInfo);
					}
				})
				.finally(() => {
					this.isLogLoading = false;
				});
		},

		renderLogRow(row, index, list) {
			// eslint-disable-next-line max-len
			const logContent = `<span class="log-header">[ ${escapeHTML(
				row.timestamp
			)} ]</span> ${escapeHTML(row.content)}`;
			const errorTypeMap = {
				// eslint-disable-next-line max-len
				[LOG_TYPE_NEED_PASSWORD]: `<span class="action" data-action="passwordRetry">${I18n.t(
					'template.输入密码'
				)}</span>`,
				// eslint-disable-next-line max-len
				[LOG_TYPE_ERROR_PASSWORD]: `<span class="action" data-action="passwordRetry">${I18n.t(
					'template.重新输入密码'
				)}</span>`,
			};
			if (row.type === LOG_TYPE_TASK_EXPIRE) {
				return `<span class="error">${logContent}</span>`;
			}
			if (index === list.length - 1 && errorTypeMap[row.type]) {
				return `<span class="error">${logContent}${errorTypeMap[row.type]}</span>`;
			}
			if (index === list.length - 1 && this.isUploadSuccess) {
				// eslint-disable-next-line max-len
				return `<span>${logContent}${I18n.t(
					'template.请点'
				)}<span class="action" data-action="success">${I18n.t('template.下一步')}</span></span>`;
			}
			return logContent;
		},

		startTimer() {
			if (this.isClearTimer) {
				return;
			}
			const currentTask = this.pollingQueue.pop();
			if (currentTask) {
				currentTask();
			}
			setTimeout(() => {
				this.startTimer();
			}, 1000);
		},

		clearTimer() {
			this.isClearTimer = true;
		},

		handleUploadRequest(option) {
			this.uploadFilename = option.fileObj.name;

			if (!/\.jobexport$/.test(option.fileObj.name)) {
				this.uploadStatus = 'error';
				this.uploadErrorMsg = I18n.t('template.文件类型不支持');
				return;
			}
			this.fileMemo = option;
			this.isShowLog = false;
			this.uploadStatus = 'waiting';
			const formData = new FormData();
			formData.append('uploadFile', option.fileObj.origin);

			BackupService.uploadImportFile(formData, {
				onUploadProgress: event => {
					const { loaded, total } = event;
					this.uploadProgress = `${Math.ceil((loaded / total) * 100)}%`;
				},
				setCancelSource: source => {
					this.uploadRequestCancelSource = source;
				},
			})
				.then(data => {
					this.id = data.id;
					taskImport.setItem('id', data.id);
					taskImport.setItem('uploadFilename', this.uploadFilename);
					this.fetchImportInfo();
					this.startTimer();
					this.uploadStatus = 'success';
				})
				.catch(() => {
					this.uploadStatus = 'failed';
				});
		},

		handleFileRefresh() {
			this.handleUploadRequest(this.fileMemo);
		},

		hanleFileDelete() {
			if (this.uploadRequestCancelSource) {
				this.uploadRequestCancelSource.cancel(I18n.t('template.上传任务已取消'));
			}
			this.uploadStatus = '';
			this.uploadFilename = '';
			this.id = '';
			this.importInfo = {
				id: '',
				log: [],
				status: 0,
				templateInfo: [],
			};
			this.isShowLog = false;
			taskImport.clearItem();
		},
		handleInputPassword() {
			this.passwordFormData.password = '';
			this.isShowPassword = true;
		},
		handleClosePassword() {
			this.isShowPassword = false;
			window.changeFlag = false;
			this.$refs.passwordForm.clearError();
			this.importInfo.log.push({
				content: I18n.t('template.导入任务已取消！需要重试请点击'),
				linkText: null,
				linkUrl: null,
				planId: null,
				templateId: null,
				timestamp: prettyDateTimeFormat(Date.now()),
				type: LOG_TYPE_ERROR_PASSWORD,
			});
		},
		handleEnter(value, event) {
			if (event.isComposing) {
				// 跳过输入发复合时间
				return;
			}
			if (event.keyCode !== 13) {
				// 非enter键
				return;
			}
			this.handleSubmitPassword();
		},
		handleSubmitPassword() {
			this.isPasswordSubmiting = true;
			this.$refs.passwordForm
				.validate()
				.then(() =>
					BackupService.checkImportPassword({
						...this.passwordFormData,
						id: this.id,
					}).then(() => {
						this.isShowPassword = false;
						window.changeFlag = false;
						this.fetchImportInfo();
					})
				)
				.finally(() => {
					this.isPasswordSubmiting = false;
				});
		},
		handleLogAction(event) {
			const $target = event.target;
			if (!$target.classList.contains('action')) {
				return;
			}
			const actionType = $target.getAttribute('data-action');
			switch (actionType) {
				case 'passwordRetry':
					this.handleInputPassword();
					break;
				case 'success':
					this.handleNext();
					break;
				default:
			}
		},
		handleCancel() {
			this.hanleFileDelete();
			this.$emit('on-cancle');
		},
		handleLast() {
			this.$emit('on-change', 1);
		},
		handleNext() {
			this.$emit('on-change', 3);
		},
	},
};
</script>
<style lang="postcss">
.task-import-step2 {
	width: 680px;
	margin: 60px auto 0;

	.upload-log-box {
		width: 680px;
		max-height: calc(100vh - 344px);
		padding: 10px 16px;
		margin-top: 20px;
		overflow-y: scroll;
		font-size: 12px;
		line-height: 22px;
		color: #979ba5;
		background: #fafbfd;
		border: 1px solid #dcdee5;
		border-radius: 2px;

		.action {
			color: var(--color-primary);
			cursor: pointer;
		}
	}

	.bk-upload {
		.all-file {
			display: none;
		}
	}

	.upload-result {
		position: relative;
		display: flex;
		height: 60px;
		padding: 12px 10px;
		cursor: pointer;
		background: #fff;
		border: 1px solid #c4c6cc;
		border-radius: 2px;

		&:hover {
			background: #f0f1f5;

			.file-delete {
				display: block;
			}
		}

		&.success {
			.file-status {
				color: #2dcb56;
			}
		}

		&.error,
		&.failed {
			background: rgb(254 221 220 / 40%);
			border-color: #ff5656;

			&:hover {
				.file-delete {
					display: block;
				}
			}

			.file-status {
				color: #ff5656;
			}

			.file-refresh,
			.file-delete {
				top: 20px;
				color: #ff5656;
			}

			.file-delte {
				right: 12px;
			}
		}

		&.failed {
			&:hover {
				.file-refresh {
					display: block;
				}
			}
		}

		.file-pic {
			width: 36px;
			height: 36px;
			background: skyblue;
		}

		.file-info {
			padding-left: 11px;
			font-size: 12px;
			line-height: 20px;
			color: #63656e;
			flex: 1;
		}

		.file-status {
			height: 16px;
			font-size: 12px;
			line-height: 16px;
		}

		.file-refresh,
		.file-delete {
			position: absolute;
			display: none;
			font-size: 20px;
			color: #979ba5;
		}

		.file-refresh {
			top: 20px;
			right: 41px;
		}

		.file-delete {
			top: 4px;
			right: 4px;
		}

		.progress-text {
			position: absolute;
			top: 18px;
			right: 18px;
			font-weight: bold;
			line-height: 16px;
			color: #63656e;
			user-select: none;
		}

		.upload-progress {
			position: relative;
			height: 2px;
			margin-top: 6px;
			background: #dcdee5;

			.progress-bar {
				position: absolute;
				top: 0;
				bottom: 0;
				left: 0;
				width: 100px;
				background: var(--color-primary);
			}
		}
	}
}

.setting-password-dialog {
	.bk-dialog-header {
		padding-bottom: 0 !important;
	}

	.bk-form-item:last-child {
		margin-bottom: 0 !important;
	}

	.setting-password-footer {
		display: flex;
		justify-content: flex-end;
	}
}
</style>
